package com.keba.lamp.base.service.user.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.keba.basic.base.request.PageParams;
import com.keba.basic.base.service.impl.SuperCacheServiceImpl;
import com.keba.basic.context.ContextUtil;
import com.keba.basic.database.mybatis.conditions.Wraps;
import com.keba.basic.database.mybatis.conditions.query.LbQueryWrap;
import com.keba.basic.model.cache.CacheKey;
import com.keba.basic.utils.ArgumentAssert;
import com.keba.lamp.base.entity.system.BaseRole;
import com.keba.lamp.base.entity.user.BaseEmployee;
import com.keba.lamp.base.entity.user.BaseEmployeeOrgRel;
import com.keba.lamp.base.entity.user.BaseEmployeeRoleRel;
import com.keba.lamp.base.manager.system.BaseRoleManager;
import com.keba.lamp.base.manager.user.BaseEmployeeManager;
import com.keba.lamp.base.manager.user.BaseEmployeeOrgRelManager;
import com.keba.lamp.base.manager.user.BaseEmployeeRoleRelManager;
import com.keba.lamp.base.service.user.BaseEmployeeService;
import com.keba.lamp.base.vo.query.user.BaseEmployeePageQuery;
import com.keba.lamp.base.vo.result.user.BaseEmployeeResultVO;
import com.keba.lamp.base.vo.save.user.BaseEmployeeRoleRelSaveVO;
import com.keba.lamp.base.vo.save.user.BaseEmployeeSaveVO;
import com.keba.lamp.base.vo.update.user.BaseEmployeeUpdateVO;
import com.keba.lamp.common.cache.base.user.EmployeeCacheKeyBuilder;
import com.keba.lamp.common.cache.base.user.EmployeeOrgCacheKeyBuilder;
import com.keba.lamp.common.cache.base.user.EmployeeRoleCacheKeyBuilder;
import com.keba.lamp.common.constant.RoleConstant;
import com.keba.lamp.system.vo.result.tenant.DefUserTenantRelResultVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 员工
 * </p>
 *
 * @author zuihou
 * @date 2021-10-18
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)

public class BaseEmployeeServiceImpl extends SuperCacheServiceImpl<BaseEmployeeManager, Long, BaseEmployee> implements BaseEmployeeService {
    private final BaseEmployeeRoleRelManager baseEmployeeRoleRelManager;
    private final BaseEmployeeOrgRelManager baseEmployeeOrgRelManager;
    private final BaseRoleManager baseRoleManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrgInfo(Long id, Long lastCompanyId, Long lastDeptId) {
        superManager.update(Wrappers.<BaseEmployee>lambdaUpdate().set(BaseEmployee::getLastCompanyId, lastCompanyId)
                .set(BaseEmployee::getLastDeptId, lastDeptId).eq(BaseEmployee::getId, id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatch(Collection<BaseEmployee> entityList) {
        return superManager.saveBatch(entityList);
    }

    @Override
    public IPage<BaseEmployeeResultVO> findPageResultVO(PageParams<BaseEmployeePageQuery> params) {
        IPage<BaseEmployee> page = params.buildPage(BaseEmployee.class);
        BaseEmployeePageQuery model = params.getModel();
        LbQueryWrap<BaseEmployee> wrap = Wraps.lbQ();
        wrap.like(BaseEmployee::getRealName, model.getRealName())
                .eq(BaseEmployee::getPositionStatus, model.getPositionStatus())
                .eq(BaseEmployee::getPositionId, model.getPositionId())
                .eq(BaseEmployee::getActiveStatus, model.getActiveStatus())
                .eq(BaseEmployee::getState, model.getState())
                .in(BaseEmployee::getUserId, model.getUserIdList());

        return superManager.selectPageResultVO(page, wrap, model);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> saveEmployeeRole(BaseEmployeeRoleRelSaveVO saveVO) {
        if (saveVO.getFlag() == null) {
            saveVO.setFlag(true);
        }
        List<Long> roleIds = saveVO.getRoleIdList();
        List<Long> adminRoleIds = new ArrayList<>();
        if (!saveVO.getFlag()) {
            adminRoleIds = baseRoleManager.list(Wraps.<BaseRole>lbQ().eq(BaseRole::getCode, RoleConstant.TENANT_ADMIN).in(BaseRole::getId, saveVO.getRoleIdList()))
                    .stream().map(BaseRole::getId).collect(Collectors.toList());
        }
        roleIds.removeAll(adminRoleIds);
        if (CollUtil.isEmpty(roleIds)) {
            return new ArrayList<>();
        }
        baseEmployeeRoleRelManager.remove(Wraps.<BaseEmployeeRoleRel>lbQ().eq(BaseEmployeeRoleRel::getEmployeeId, saveVO.getEmployeeId())
                .in(BaseEmployeeRoleRel::getRoleId, roleIds));

        if (saveVO.getFlag() && CollUtil.isNotEmpty(roleIds)) {
            List<BaseEmployeeRoleRel> list = roleIds.stream()
                    .map(roleId -> BaseEmployeeRoleRel.builder()
                            .roleId(roleId).employeeId(saveVO.getEmployeeId())
                            .build()).toList();
            baseEmployeeRoleRelManager.saveBatch(list);
        }

        cacheOps.del(EmployeeRoleCacheKeyBuilder.build(saveVO.getEmployeeId()));
        return findEmployeeRoleByEmployeeId(saveVO.getEmployeeId());
    }

    @Override
    public List<BaseEmployee> listByUserId(Long userId) {
        return superManager.list(Wrappers.<BaseEmployee>lambdaQuery().eq(BaseEmployee::getUserId, userId));
    }

    @Override
    public List<BaseEmployee> listByUserIds(Collection<Long> userIds) {
        return superManager.list(Wrappers.<BaseEmployee>lambdaQuery().in(BaseEmployee::getUserId, userIds));
    }

    @Override
    public List<Long> findEmployeeRoleByEmployeeId(Long employeeId) {
        return baseEmployeeRoleRelManager.listObjs(Wrappers.<BaseEmployeeRoleRel>lambdaQuery()
                        .select(BaseEmployeeRoleRel::getRoleId)
                        .eq(BaseEmployeeRoleRel::getEmployeeId, employeeId),
                Convert::toLong
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public <SaveVO> BaseEmployee save(SaveVO saveVO) {
        BaseEmployeeSaveVO employeeSaveVO = (BaseEmployeeSaveVO) saveVO;
        BaseEmployee baseEmployee = BeanUtil.toBean(employeeSaveVO, BaseEmployee.class);
        baseEmployee.setCreatedOrgId(ContextUtil.getCurrentDeptId());
        superManager.save(baseEmployee);
        List<Long> orgIdList = employeeSaveVO.getOrgIdList();
        saveEmployeeOrg(baseEmployee, orgIdList);
        return baseEmployee;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public <UpdateVO> BaseEmployee updateById(UpdateVO updateVO) {
        BaseEmployeeUpdateVO employeeUpdateVO = (BaseEmployeeUpdateVO) updateVO;
        BaseEmployee baseEmployee = BeanUtil.toBean(updateVO, BaseEmployee.class);
        superManager.updateById(baseEmployee);
        List<Long> orgIdList = employeeUpdateVO.getOrgIdList();

        saveEmployeeOrg(baseEmployee, orgIdList);
        return baseEmployee;
    }

    private void saveEmployeeOrg(BaseEmployee baseEmployee, List<Long> orgIdList) {
        baseEmployeeOrgRelManager.removeByEmployeeId(baseEmployee.getId());
        if (CollUtil.isNotEmpty(orgIdList)) {
            List<BaseEmployeeOrgRel> eoList = orgIdList.stream().map(orgId ->
                    BaseEmployeeOrgRel.builder()
                            .employeeId(baseEmployee.getId())
                            .orgId(orgId)
                            .build()).toList();
            baseEmployeeOrgRelManager.saveBatch(eoList);
        }

        cacheOps.del(EmployeeOrgCacheKeyBuilder.build(baseEmployee.getId()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<Long> idList) {
        boolean flag = superManager.removeByIds(idList);
        baseEmployeeOrgRelManager.removeByEmployeeIds(idList);
        baseEmployeeRoleRelManager.removeByEmployeeIds(idList);
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatchBaseEmployeeAndRole(List<BaseEmployee> employeeList) {
        ArgumentAssert.notEmpty(employeeList, "员工列表不能为空");
        superManager.saveBatch(employeeList);

        List<Long> employeeIdList = employeeList.stream().map(BaseEmployee::getId).toList();
        return baseEmployeeRoleRelManager.bindRole(employeeIdList, RoleConstant.TENANT_ADMIN);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDefaultTenant(Long tenantId, Long userId) {
        ArgumentAssert.notNull(userId, "用户id不能为空");
        ArgumentAssert.notNull(tenantId, "企业id不能为空");

        // 演示环境专用标识，用于WriteInterceptor拦截器判断演示环境需要禁止用户执行sql，若您无需搭建演示环境，可以删除下面一行代码
        if (Long.valueOf(1).equals(ContextUtil.getTenantId())) {
            ContextUtil.setStop();
        }
        List<BaseEmployee> list = superManager.listIgnore(Wraps.<BaseEmployee>lbQ().eq(BaseEmployee::getUserId, userId));
        CacheKey[] keyList = list.stream().map(item -> EmployeeCacheKeyBuilder.build(item.getId())).toArray(CacheKey[]::new);
        cacheOps.del(keyList);

        superManager.updateIgnore(Wraps.<BaseEmployee>lbU()
                .set(BaseEmployee::getIsDefault, false)
                .eq(BaseEmployee::getUserId, userId));

        return superManager.updateIgnore(Wraps.<BaseEmployee>lbU()
                .set(BaseEmployee::getIsDefault, true)
                .eq(BaseEmployee::getUserId, userId)
                .eq(BaseEmployee::getTenantId, tenantId)
        );
    }

    @Override
    public BaseEmployee getEmployeeByTenantAndUser(Long tenantId, Long userId) {
        ArgumentAssert.notNull(tenantId, "租户id为空");
        ArgumentAssert.notNull(userId, "用户id为空");
        return superManager.getEmployeeByTenantAndUser(tenantId, userId);
    }

    @Override
    public long countIgnore(Wrapper<BaseEmployee> queryWrapper) {
        return superManager.countIgnore(queryWrapper);
    }

    @Override
    public List<BaseEmployee> listIgnore(Wrapper<BaseEmployee> wrapper) {
        return superManager.listIgnore(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(BaseEmployee baseEmployee) {
        return superManager.updateById(baseEmployee);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateAllById(BaseEmployee baseEmployee) {
        return superManager.updateAllById(baseEmployee);
    }

    @Override
    public List<DefUserTenantRelResultVO> listEmployeeByUserId(Long userId) {
        return superManager.listEmployeeByUserId(userId);
    }

    @Override
    public List<DefUserTenantRelResultVO> listEmployeeByUserIdAndTenantId(Long userId, Long tenantId) {
        return superManager.listEmployeeByUserIdAndTenantId(userId, tenantId);
    }
}
